/** **************************************************
 * Description: 利用Oracle的sequence生成序列号
 * Copyright:   Copyright (c) 2008
 * Company:    cl
 * @author     caoxl
 * @version    1.0
 * @see
 HISTORY
 *  2008-7-1 caoxl Create File
 ************************************************* */
package com.bfsuol.bfsuolframework.core.dao.keygen;

import com.bfsuol.bfsuolframework.core.spring.SpringBeanLoader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class OracleSequenceKeyGen implements KeyGen, InitializingBean{

	private DataSource dataSource;//数据库连接
	public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}
	public DataSource getDataSource() {return this.dataSource;}

	public void afterPropertiesSet() {
		if (this.dataSource == null) {
			throw new IllegalArgumentException("必须输入数据源");
		}
	}
	
	/**
	 * 获得下一个序列值
	 * @param key 键
	 * @param start 起始值
	 * @param maxValue 最大值
	 * @param incrementer 增长幅度
	 * @return 下一个序列值
	 */
	public long getNextValue(String key,int start,int maxValue,int incrementer){
		return this.getNextValue(key, start, maxValue, incrementer, true);
	}

	/**
	 * 通过oracle的sequence获得下一个序列值
	 * @param key
	 * @param start
	 * @param maxValue
	 * @param incrementer
	 * @param ignoreError
	 * @return
	 * @throws DataAccessException
	 */
	public long getNextValue(String key,int start,int maxValue,int incrementer,boolean ignoreError) throws DataAccessException {
		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stmt = null;
		ResultSet rs = null;
		try {
			stmt = con.createStatement();
			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
			rs = stmt.executeQuery("select keygen_" + key + ".nextval from dual");
			if (rs.next()) {
				return rs.getLong(1);
			}
			else {
				if(ignoreError){
					dropSequence(key);
					createSequence(key,start,maxValue,incrementer);
					return getNextValue(key,start,maxValue,incrementer,false);
				}else{
					throw new DataAccessResourceFailureException("Sequence query did not return a result");
				}
			}
		}
		catch (SQLException e) {
			if(ignoreError){
				createSequence(key,start,maxValue,incrementer);
				return getNextValue(key,start,maxValue,incrementer,false);
			}else{
				throw new DataAccessResourceFailureException("Could not obtain sequence value", e);
			}
		}
		finally {
			JdbcUtils.closeResultSet(rs);
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}

	/**
	 * 创建新的sequence
	 * @param key
	 * @param start
	 * @param maxValue
	 * @param incrementer
	 */
	protected void createSequence(String key,int start,int maxValue,int incrementer) {
		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stmt = null;
		StringBuffer sql = new StringBuffer();
		sql.append("create sequence keygen_").append(key);
		if(incrementer>0){
			sql.append(" increment by ").append(incrementer);
		}
		if(start > 0){
			sql.append(" start with ").append(start);
		}
		if(maxValue > 0 && maxValue > start){
			sql.append(" maxvalue ").append(maxValue);
		}
		sql.append(" nocache");
		try {
			stmt = con.createStatement();
			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
			stmt.executeUpdate(sql.toString());
		}
		catch (SQLException ex) {
			//throw new DataAccessResourceFailureException("create sequence fail !", ex);
		}
		finally {
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
	
	/**
	 * 删除sequence
	 * @param key
	 */
	protected void dropSequence(String key) {
		Connection con = DataSourceUtils.getConnection(getDataSource());
		Statement stmt = null;
		try {
			stmt = con.createStatement();
			DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
			stmt.executeUpdate("drop sequence keygen_" + key);
		}
		catch (SQLException ex) {
			//throw new DataAccessResourceFailureException("drop sequence fail !", ex);
		}
		finally {
			JdbcUtils.closeStatement(stmt);
			DataSourceUtils.releaseConnection(con, getDataSource());
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		OracleSequenceKeyGen kg = (OracleSequenceKeyGen) SpringBeanLoader.getBean("KeyGen");
		
		System.out.println(kg.getNextValue("aaa",1,0,1,true));
	}

}
